<template>
  <div class="wrap">
    <canvas id="renderCanvas"></canvas>
  </div>
</template>

<script>
import * as BABYLON from "babylonjs"; //全部引入
import * as GEOLIB from "geolib"; // 处理经纬度数据 算出两点之间的距离和角度
// import addVideoTex from "./js/videoTexture"; // 视频纹理
import addImgTex from "./js/imageTexture"; // 图片纹理
import addDrone from "./js/addDrone"; // 添加无人机
// import addSimpleCar from "./js/addSimpleCar"; // 添加小车
// import line2D from "./js/line2D"; // 带有宽度的线
import dyTex from "./js/dyTex"; // 动态纹理
// import getPath from "./js/getPath"; // 直线路径

export default {
  name: "buildingCom",
  data() {
    return {
      light1: null,
      light2: null,
      sphere: null,
      engine: null,
      scene: null,
      canvas: null,
      myMaterial: null,
      myMaterial2: null,
      center: [116.9713414, 36.6497103]
    };
  },
  props: {
    msg: String
  },
  beforeDestroy() {
    // this.scene = null;
    // this.engine = null;
    while (this.engine.scenes.length) {
      console.log(this.engine.scenes.length, "让我看看aaa2");
      this.engine.scenes[0].dispose();
    }
    this.engine.dispose();
    this.engine = null;
  },
  methods: {
    // 获取geo数据
    getGeoJson(scene) {
      fetch("./static/geoJson/hexie2.geojson").then(res => {
        res.json().then(data => {
          console.log(data, "data");
          // 构建建筑路网
          this.loadBuilding(data);
          // 添加视频纹理
          // addVideoTex(scene);
          // 添加图片纹理
          addImgTex(scene);
          // 添加动态纹理
          this.addDynamicTex(scene);
          // 使用动态纹理添加二维圆环扩散
          this.addDynamicTex2(scene);
          // 添加曲线
          this.addCurve(scene);
          // 添加圆柱体
          this.addCy(scene);
          // 添加圆锥体
          this.addCy2(scene);
          // 添加动态纹理  圆旋转
          dyTex(scene);
          // 添加地面
          // this.addGround(scene);
          // 添加粒子效果，数字柱
          this.addParitce(scene, new BABYLON.Vector3(2, 0, 2));
          this.addParitce(scene, new BABYLON.Vector3(2, 0, 1));
          // 粒子柱
          // this.addParitce2(scene);
          // 选中几个建筑添加发光材质
          // let heXieBuilding = scene.getMeshByName("和谐广场南座");
          // heXieBuilding.material = this.myMaterial;
        });
      });
    },
    addParitce2(scene) {
      var particleSystem = new BABYLON.ParticleSystem("particles", 2000, scene);

      //Texture of each particle
      particleSystem.particleTexture = new BABYLON.Texture(
        "https://minio.cnbabylon.com/public/Assets/Flare.png",
        scene
      );

      // Where the particles come from
      particleSystem.emitter = new BABYLON.Vector3(-0.5, 0, -3); // the starting location

      // Colors of all particles
      particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
      particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
      particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);

      // Size of each particle (random between...
      particleSystem.minSize = 0.05;
      particleSystem.maxSize = 0.2;

      // Life time of each particle (random between...
      particleSystem.minLifeTime = 0.3;
      particleSystem.maxLifeTime = 1.5;

      // Emission rate
      particleSystem.emitRate = 10;

      /******* Emission Space ********/
      particleSystem.createPointEmitter(
        new BABYLON.Vector3(0, 1, 0),
        new BABYLON.Vector3(0, 1, 0)
      );

      // Speed
      particleSystem.minEmitPower = 1;
      particleSystem.maxEmitPower = 3;
      particleSystem.updateSpeed = 0.005;

      // Start the particle system
      particleSystem.start();
    },
    addParitce(scene, pos) {
      var particleSystem = new BABYLON.ParticleSystem("particles", 20, scene);

      //Texture of each particle
      particleSystem.particleTexture = new BABYLON.Texture(
        "static/textures/flyNum.png",
        scene
      );

      // Where the particles come from
      particleSystem.emitter = pos; // the starting location
      // 融合方式
      // particleSystem.emitter.position = new BABYLON.Vector3(3, 0, 5);
      particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_STANDARD;
      // Colors of all particles
      particleSystem.color1 = new BABYLON.Color4(1, 0.95, 0.3, 1.0);
      particleSystem.color2 = new BABYLON.Color4(1, 0.95, 0.0, 1.0);
      particleSystem.colorDead = new BABYLON.Color4(1, 0.95, 0.0, 1.0);

      // Size of each particle (random between...
      // particleSystem.minSize = 0.1;
      // particleSystem.maxSize = 0.5;
      particleSystem.minScaleX = 0.2;
      particleSystem.maxScaleX = 0.2;

      particleSystem.minScaleY = 1;
      particleSystem.maxScaleY = 1;

      // Life time of each particle (random between...
      particleSystem.minLifeTime = 3;
      particleSystem.maxLifeTime = 4;

      // Emission rate
      particleSystem.emitRate = 2;

      /******* Emission Space ********/
      particleSystem.createPointEmitter(
        new BABYLON.Vector3(0, 1, 0),
        new BABYLON.Vector3(0, 1, 0)
      );

      // Speed
      particleSystem.minEmitPower = 3;
      particleSystem.maxEmitPower = 4;
      particleSystem.updateSpeed = 0.005;
      particleSystem.isLocal = true;
      // Start the particle system
      particleSystem.start();
    },
    addGround(scene) {
      const mat = new BABYLON.StandardMaterial("M");
      mat.diffuseTexture = new BABYLON.Texture("static/textures/plane.png");

      const pat = BABYLON.Mesh.FLIP_TILE;

      const options = {
        sideOrientation: BABYLON.Mesh.DOUBLESIDE,
        pattern: pat,
        width: 40,
        height: 40,
        tileSize: 0.2,
        tileWidth: 0.2
      };

      const tiledPane = BABYLON.MeshBuilder.CreateTiledPlane(
        "tilePlane",
        options,
        scene
      );
      tiledPane.material = mat;
      tiledPane.material.diffuseTexture.hasAlpha = true;
      tiledPane.rotation.x = Math.PI / 2;
    },
    // 创建圆锥体
    addCy2(scene) {
      const cy2 = BABYLON.MeshBuilder.CreateCylinder(
        "cy2",
        { height: 0.26, diameterTop: 0, diameterBottom: 0.3, tessellation: 4 },
        scene
      );
      cy2.position = new BABYLON.Vector3(4, 0.4, -3);
      cy2.rotation.x = Math.PI;
      cy2.material = new BABYLON.StandardMaterial("M", scene);
      cy2.material.emissiveColor = new BABYLON.Color3(1, 0.6, 0);
      // 动画帧
      let keys = [
        {
          frame: 0,
          value: new BABYLON.Vector3(4, 0.2, -3)
        },
        {
          frame: 50,
          value: new BABYLON.Vector3(4, 0.4, -3)
        },
        {
          frame: 100,
          value: new BABYLON.Vector3(4, 0.2, -3)
        }
      ];
      // 圆锥上下移动动画
      var animationUp = new BABYLON.Animation(
        "animationUp",
        "position",
        30,
        BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
        BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
      );
      animationUp.setKeys(keys);
      cy2.animations = [];
      cy2.animations.push(animationUp);
      // 参数5动画播放速度
      scene.beginAnimation(cy2, 0, 100, true, 1);
    },
    getCurvePath(originXY, destinationXY) {
      let controlXY = [
        originXY[0] + 0.3 * (destinationXY[0] - originXY[0]),
        originXY[1] + 0.3 * (destinationXY[1] - destinationXY[1])
      ];
      let origin = new BABYLON.Vector3(originXY[0], 0, originXY[1]);
      let destination = new BABYLON.Vector3(
        destinationXY[0],
        0,
        destinationXY[1]
      );
      let control = new BABYLON.Vector3(controlXY[0], 4, controlXY[1]);
      let nb_of_points = 20;
      let bezier2 = BABYLON.Curve3.CreateQuadraticBezier(
        origin,
        control,
        destination,
        nb_of_points
      );
      let curvePath = bezier2.getPoints();
      return curvePath;
    },
    createCurve(originXY, destinationXY) {
      let curvePath = this.getCurvePath(originXY, destinationXY);
      const line = BABYLON.MeshBuilder.CreateLines("curlines", {
        points: curvePath
      });
      line.color = new BABYLON.Color3(1, 0.5, 0.5);
      line.alpha = 0.5;
      return line;
    },
    // 创建虚线
    createDashCurve(originXY, destinationXY) {
      let curvePath = this.getCurvePath(originXY, destinationXY);
      // 虚线配置项
      let options = {
        // 坐标数组
        points: curvePath,
        // 虚线尺寸
        dashSize: 1000,
        // 虚线之间的距离
        gapSize: 500,
        // 虚线段数量
        dashNb: 20
      };
      const dashLine = BABYLON.MeshBuilder.CreateDashedLines("lines", options);
      dashLine.color = new BABYLON.Color3.Green();
      return dashLine;
    },
    // 创建带有宽度的线
    createline2D(originXY, destinationXY, scene) {
      let curvePath = this.getCurvePath(originXY, destinationXY);
      // 二维线
      // let curvePath = getPath(
      //   [
      //     [2, 0],
      //     [-3, -3]
      //   ],
      //   0.1
      // );
      // 创建管子， 三维管道线
      var line = BABYLON.MeshBuilder.CreateTube(
        "tube",
        { path: curvePath, radius: 0.02 },
        scene
      );
      // 带有宽度的二维线
      // const line = line2D("line2D", {
      //   path: curvePath,
      //   width: 0.06
      // });
      let lineMat = new BABYLON.StandardMaterial("lineMat");
      lineMat.diffuseTexture = new BABYLON.Texture(
        "static/textures/flash2.png"
      );
      lineMat.emissiveColor = new BABYLON.Color3(0.6, 0.8, 1);
      // lineMat.diffuseTexture.uScale = 15.0;
      line.material = lineMat;
      scene.registerBeforeRender(() => {
        // console.log(lineMat.diffuseTexture, "为什么");
        lineMat.diffuseTexture.vOffset -= 0.02;
      });
    },
    // 创建圆柱体
    addCy(scene) {
      const myPath = [
        new BABYLON.Vector3(0, 0, 0),
        new BABYLON.Vector3(0, 0.5, 0)
      ];
      let cy = BABYLON.MeshBuilder.CreateTube(
        "tube",
        { path: myPath, radius: 0.5, sideOrientation: BABYLON.Mesh.DOUBLESIDE },
        scene
      );
      // cy.position.y = 0.3;
      cy.material = new BABYLON.StandardMaterial("M", scene);
      cy.material.diffuseTexture = new BABYLON.Texture(
        "static/textures/cyTex.png"
      );
      cy.material.alpha = 0.7;
      cy.material.emissiveColor = new BABYLON.Color3(0, 0.8, 1);
      cy.material.diffuseTexture.hasAlpha = true;
      scene.registerBeforeRender(() => {
        cy.scaling.x > 5 ? (cy.scaling.x = 1) : (cy.scaling.x += 0.1);
        cy.scaling.z > 5 ? (cy.scaling.z = 1) : (cy.scaling.z += 0.1);
        // console.log(cy);
      });
    },
    // 创建飞线
    addCurve(scene) {
      // 添加曲线
      this.createCurve([0, 0], [6, -5]);
      // 添加曲线（虚线)
      this.createDashCurve([0, 0], [6, -5]);
      this.createCurve([0, 0], [-3, 5]);
      // 添加有宽度得线
      this.createline2D([0, 0], [6, -5], scene);
    },
    // 使用动态纹理实现地面上二维圆扩散效果
    addDynamicTex2(scene) {
      let dynamicTex = new BABYLON.DynamicTexture(
        "dynamicTex",
        { height: 100, width: 100 },
        scene,
        true
      );

      let planeOpts = {
        height: 0.5,
        width: 0.5,
        sideOrientation: 0
      };
      let textBoard = BABYLON.MeshBuilder.CreatePlane(
        "textBoard",
        planeOpts,
        scene
      );
      textBoard.position = new BABYLON.Vector3(-3, 0, 5);
      textBoard.rotation.x = Math.PI / 2;
      textBoard.material = new BABYLON.StandardMaterial("M", scene);
      // textBoard.material.alpha = 0.3;
      textBoard.material.diffuseTexture = dynamicTex;
      // 这样设置透明没效果，有点意思, 字写错了 nb
      textBoard.material.diffuseTexture.hasAlpha = true;
      // 动态纹理这样可以设置成透明
      // dynamicTex.hasAlpha = true;
      // textBoard.material.backFaceCulling = false;
      textBoard.material.emissiveColor = new BABYLON.Color3.Red();
      let radiu = 25;
      let alpha = 1;
      scene.registerBeforeRender(() => {
        let ctx = dynamicTex.getContext();
        ctx.clearRect(0, 0, 100, 100);
        // ctx.fillStyle = "rgba(51, 51, 76, 1)";
        // ctx.fillRect(0, 0, 100, 100);
        ctx.beginPath();
        ctx.fillStyle = "#713030";
        ctx.arc(50, 50, 20, 0, Math.PI * 2, false);
        ctx.fill();
        ctx.beginPath();
        ctx.lineWidth = 10;
        ctx.strokeStyle = `rgba(114, 50, 50, ${alpha})`;
        // console.log(ctx.strokeStyle, "stroke");
        // 绘制圆的路径**
        ctx.arc(50, 50, radiu, 0, Math.PI * 2, false);

        // 0°是从三点钟方向开始的

        // 描边路径
        ctx.stroke();
        dynamicTex.update();
        alpha < 0 ? (radiu = 25) : (radiu += 1);
        alpha < 0 ? (alpha = 1) : (alpha -= 0.04);
        // ctx.fillStyle = #713030;
      });
    },
    // 创建动态纹理
    addDynamicTex(scene) {
      // 定义一个动态纹理
      let dynamicTex = new BABYLON.DynamicTexture(
        "dynamicTex",
        {
          height: 132,
          width: 512
        },
        scene,
        true
      );

      let planeOpts = {
        height: 0.1,
        width: 0.3,
        sideOrientation: 0
      };
      // 创建一个平面
      let textBoard = BABYLON.MeshBuilder.CreatePlane(
        "textBoard",
        planeOpts,
        scene
      );
      textBoard.position = new BABYLON.Vector3(-0.3, 0.2, -2.9);
      textBoard.rotation.y = Math.PI / 2;
      // 为平面添加材质
      textBoard.material = new BABYLON.StandardMaterial("textBoardMat", scene);
      // // 设置纹理  材质加纹理
      textBoard.material.diffuseTexture = dynamicTex;
      // 材质加自发光
      textBoard.material.emissiveColor = new BABYLON.Color3.White();
      let textPosX = 512;
      scene.registerBeforeRender(() => {
        textPosX < -520 ? (textPosX = 512) : (textPosX -= 10);
        dynamicTex.clear();
        dynamicTex.drawText(
          "我是测试文字",
          textPosX,
          100,
          "normal 100px Arial",
          "red",
          "black"
        );
      });
    },
    loadBuilding(data) {
      // 有用的数据只有data中的features
      let features = data.features;

      for (let i = 0; i < features.length; i++) {
        let fel = features[i];

        if (!fel["properties"]) return;

        let info = fel.properties;

        if (info["building"]) {
          this.addBuilding(
            fel.geometry.coordinates,
            info,
            info["building:levels"]
          );
        } else if (info["highway"]) {
          if (fel.geometry.type == "LineString") {
            this.addRoad(fel.geometry.coordinates, info);
          }
        }
      }
    },
    // 添加路网
    addRoad(data, info) {
      let points = [];
      for (let i = 0; i < data.length; i++) {
        // 如果不是二维数组
        if (!data[0][1]) return;
        let el = data[i];
        if (!el[0] || !el[1]) return;

        let elp = [el[0], el[1]];

        elp = this.gpsRelativePosition(elp, this.center);

        points.push(new BABYLON.Vector3(elp[0], 0, elp[1]));
      }
      const lines = BABYLON.MeshBuilder.CreateLines("lines", {
        points: points
      });
      lines.rotation.z = Math.PI;
      lines.info = info;
      lines.color = new BABYLON.Color3(0.31, 0.31, 0.92);
    },

    addBuilding(data, info, height = 7) {
      for (let i = 0; i < data.length; i++) {
        let el = data[i];

        let shape = this.getShape(el, this.center);
        const building = BABYLON.MeshBuilder.ExtrudePolygon("building", {
          shape: shape,
          depth: 0.05 * height,
          sideOrientation: BABYLON.Mesh.DOUBLESIDE
        });
        building.rotation.z = Math.PI;
        // building.material = this.myMaterial2;
        building.name = info["name"] ? info["name"] : "building";
        building.info = info;
        // building.material = this.buildingMat;
        // building.rotation.x = Math.PI;
        // console.log(shape, height, "1");
        // const name =
      }
    },
    getShape(points, center) {
      let shape = [];

      for (let i = 0; i < points.length; i++) {
        let elp = points[i];

        elp = this.gpsRelativePosition(elp, center);

        shape.push(new BABYLON.Vector3(elp[0], 0, elp[1]));
      }
      return shape;
    },
    gpsRelativePosition(objPos, centerPos) {
      // 获取 gps 距离
      let dis = GEOLIB.getDistance(objPos, centerPos);

      // 获取夹角
      let bearing = GEOLIB.getRhumbLineBearing(objPos, centerPos);

      // 计算x
      let x = centerPos[0] + dis * Math.cos((bearing * Math.PI) / 180);

      // 计算y
      let y = centerPos[1] + dis * Math.sin((bearing * Math.PI) / 180);

      return [x / 100, y / 100];
    },
    // 按原始坐标绘制的话，两点之间经纬度差别小，并且坐标点很大数值很大，远离3d引擎的坐标原点（0, 0, 0），需要进行坐标转换，设定中心点，算出各个经纬度点相对中心点的相对坐标
    // 因为地球是球面，小范围内用经纬度点减去原点坐标，不会有相对距离偏差，如果范围大就要将球面坐标，做平面投影，常用的是墨卡托投影

    // babylon创建场景
    /******* Add the create scene function ******/
    createScene() {
      // 创建一个场景scene
      var scene = new BABYLON.Scene(this.engine);

      // 添加一个相机，并绑定鼠标事件
      var camera = new BABYLON.ArcRotateCamera(
        "Camera",
        3.75,
        1,
        10,
        new BABYLON.Vector3(0, 0, 0),
        scene
      );
      camera.attachControl(this.canvas, true);
      camera.upperBetaLimit = Math.PI / 2.2;

      // 添加一组灯光到场景
      this.light1 = new BABYLON.HemisphericLight(
        "light1",
        new BABYLON.Vector3(1, 1, 0),
        scene
      );
      //   this.light2 = new BABYLON.PointLight(
      //     "light2",
      //     new BABYLON.Vector3(0, 1, -1),
      //     scene
      //   );
      this.myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
      this.myMaterial2 = new BABYLON.StandardMaterial("myMaterial2", scene);
      this.myMaterial2.diffuseColor = new BABYLON.Color3(0.2, 0.5, 0.9);
      this.myMaterial.emissiveColor = new BABYLON.Color3(0.5, 0.9, 1);
      // this.myMaterial.diffuseTexture = new BABYLON.Texture(
      //   "static/textures/cyTex2.png"
      // );
      // this.myMaterial.alpha = 0.5;
      this.buildingMat = new BABYLON.StandardMaterial("buildingMat", scene);
      // this.buildingMat.diffuseTexture = new BABYLON.Texture("")
      // this.buildingMat.diffuseColor = new BABYLON.Color3.gray();
      this.getGeoJson(scene);
      addDrone(scene);
      // this.addCar(scene);
      // addSimpleCar(scene);

      // 创建发光图层  使得物体的 控制物体的emissiveColor 自发光强度，若没有这个图层，亮度自发光亮度无法调节  这个也叫辉光
      let gl = new BABYLON.GlowLayer("glow", scene);
      gl.intensity = 0.5;

      scene.onPointerDown = (evt, pickResult) => {
        // if the click hits the ground object, we change the impact position
        if (pickResult.hit) {
          // impact.position.x = pickResult.pickedPoint.x;
          // impact.position.y = pickResult.pickedPoint.y;
          console.log(pickResult.hit, "hit啥", pickResult);
          if (pickResult.pickedMesh.name !== "plane") {
            pickResult.pickedMesh.material = this.myMaterial;
          }
        }
      };
      // 使用粒子系统助手创建粒子系统
      // BABYLON.ParticleHelper.CreateAsync("rain", scene, false).then(set => {
      //   set.start();
      // });

      return scene;
    }
  },
  mounted() {
    this.canvas = document.getElementById("renderCanvas"); // 得到canvas对象的引用
    this.engine = new BABYLON.Engine(this.canvas, true); // 初始化 BABYLON 3D engine
    // 若需要高光图层
    // this.engine = new BABYLON.Engine(this.canvas, true, { stencil: true });

    /******* End of the create scene function ******/

    this.scene = this.createScene(); //Call the createScene function

    // 最后一步调用engine的runRenderLoop方案，执行scene.render()，让我们的3d场景渲染起来
    this.engine.runRenderLoop(() => {
      this.scene.render();
    });

    // 监听浏览器改变大小的事件，通过调用engine.resize()来自适应窗口大小
    window.addEventListener("resize", () => {
      this.engine.resize();
    });
    console.log("first");
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.wrap {
  height: 100vh;
  width: 100vw;

  #renderCanvas {
    height: 100%;
    width: 100%;
  }
}
</style>
